#ifndef	_ARH_KONTEKST_H_
#define	_ARH_KONTEKST_H_

#include "tipovi.h"

#define	POC_REG_STANJA	0x0202	//IF postavljen - dozvoljeni prekidi

//'stog' mora biti varijabla!
#define POCETAK_STOGA(stog, vel)	((void *) (((void *) stog) + (vel)))

#define STAVI_NA_STOG(stog, pod)	{	uint32 *ps = stog;	 \
						*(--ps) = (uint32) (pod);\
						stog = ps;		 \
					}

//konteks dretve - ono sto se na stogu nalazi kada se mjenja dretva (kada se 
//prekine te kasnije obnovi)
typedef struct _kontekst_dretve_t_ {
	uint32 registri[8];
	uint32 kod_greske;
	uint32 eip;
	uint32 cs;
	uint32 eflags;
} __attribute__((__packed__)) kontekst_dretve_t;


//prosirenje konteksta kada se pri povratku u dretvu prije treba odraditi neki
//dogadjaj.
typedef struct _prosiri_kontekst_dretve_t_ {
	kontekst_dretve_t kontekst;
	uint32 eip2;
	uint32 parametar1;
	uint32 parametar2;
	uint32 parametar3;
} __attribute__((__packed__)) prosireni_kontekst_dretve_t;

// stog dretve mora biti spreman za povratak iz prekida
// na njemu moraju biti, redom od dna prema vrhu:
// eflags, cs, ip, greska (kad se udje u prekidnu funkciju tako izgleda stog)
// eax - edi (rezultat "pushal")
static inline void *arh_izgradi_prekidni_stog (void *stog, void *pb)
{
	kontekst_dretve_t *pstog = (stog - sizeof(kontekst_dretve_t));

	pstog->eflags = POC_REG_STANJA; /* registar stanja */

	/* segment koda, isti kao i trenutni */
	__asm__ __volatile__("pushl %%cs\n\t" "popl %0\n\t": : "m" (pstog->cs));

	pstog->eip = (uint32) pb;	/* programsko br. */

	pstog->kod_greske = 0;	/* zamjenski kod greske */
	
	/* sadrzaj opcih registara je nebitan */

	return pstog;
}

static inline void *arh_dodaj_obradu (void *stog, void *obrada,
					void *p1, void *p2, void *p3)
{
	prosireni_kontekst_dretve_t *prkon;
	kontekst_dretve_t *pstog;
	int i;
	
	pstog = stog;
	prkon = stog - sizeof(prosireni_kontekst_dretve_t);

	for (i = 0; i < 8; i++)
		prkon->kontekst.registri[i] = 0;
	
	prkon->kontekst.kod_greske	= 0;
	prkon->kontekst.eip		= (uint32) obrada;
	prkon->kontekst.cs		= pstog->cs;
	prkon->kontekst.eflags		= POC_REG_STANJA;

	prkon->eip2 = 0;
	prkon->parametar1 = (uint32) p1;
	prkon->parametar2 = (uint32) p2;
	prkon->parametar3 = (uint32) p3;
	
	return prkon;
}


#endif	/* _ARH_KONTEKST_H_ */

/*

http://www.angelcode.com/dev/callconv/callconv.html
http://en.wikipedia.org/wiki/X86_calling_conventions

*/